import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';
import { MavenUtils } from './mavenUtils';

export class TestRunner {
    private mavenUtils: MavenUtils;
    
    constructor() {
        this.mavenUtils = new MavenUtils();
    }
    
    /**
     * 运行或调试当前测试文件
     * @param debug 是否调试模式
     */
    public async runCurrentTest(debug: boolean): Promise<void> {
        const editor = vscode.window.activeTextEditor;
        if (!editor) {
            vscode.window.showErrorMessage('没有打开的文件');
            return;
        }
        
        const filePath = editor.document.fileName;
        
        // 检查是否是Java文件
        if (!filePath.endsWith('.java')) {
            vscode.window.showErrorMessage('当前文件不是Java测试文件');
            return;
        }
        
        try {
            // 解析测试类名和包名
            const classInfo = await this.parseJavaFile(filePath);
            if (!classInfo) {
                vscode.window.showErrorMessage('无法解析测试类信息');
                return;
            }
            
            // 查找POM文件
            const pomFile = await this.findPomFile(filePath);
            if (!pomFile) {
                vscode.window.showErrorMessage('找不到关联的POM文件');
                return;
            }
            
            // 构建测试命令
            const testName = `${classInfo.packageName}.${classInfo.className}`;
            let mavenCommand = `test -Dtest=${testName}`;
            
            if (debug) {
                // 添加Surefire调试参数
                mavenCommand += ' -Dmaven.surefire.debug';
            }
            
            // 在终端中执行
            const terminal = vscode.window.createTerminal(`Maven Test: ${classInfo.className}`);
            const mvn = await this.mavenUtils.getMavenExecutable();
            const pomDir = path.dirname(pomFile);
            
            terminal.sendText(`cd "${pomDir}"`);
            terminal.sendText(`${mvn} ${mavenCommand}`);
            terminal.show();
            
            if (debug) {
                // 提示用户连接到调试器
                vscode.window.showInformationMessage('Maven调试会话已启动，请使用调试器连接到端口5005');
            }
            
        } catch (error) {
            vscode.window.showErrorMessage(`运行测试失败: ${error}`);
        }
    }
    
    /**
     * 解析Java文件，提取类名和包名
     */
    private async parseJavaFile(filePath: string): Promise<{ className: string, packageName: string } | null> {
        try {
            const content = await fs.promises.readFile(filePath, 'utf8');
            
            // 提取包名
            const packageMatch = content.match(/package\s+([\w.]+)\s*;/);
            if (!packageMatch) {
                vscode.window.showWarningMessage('无法解析包名');
                return null;
            }
            
            // 提取类名
            const classMatch = content.match(/public\s+class\s+(\w+)/);
            if (!classMatch) {
                vscode.window.showWarningMessage('无法解析类名');
                return null;
            }
            
            return {
                packageName: packageMatch[1],
                className: classMatch[1]
            };
            
        } catch (error) {
            console.error('解析Java文件失败:', error);
            return null;
        }
    }
    
    /**
     * 查找与Java文件关联的POM文件
     */
    private async findPomFile(javaFilePath: string): Promise<string | undefined> {
        let currentDir = path.dirname(javaFilePath);
        
        // 向上查找直到找到pom.xml文件或到达根目录
        while (currentDir && currentDir !== path.dirname(currentDir)) {
            const pomPath = path.join(currentDir, 'pom.xml');
            
            if (fs.existsSync(pomPath)) {
                return pomPath;
            }
            
            currentDir = path.dirname(currentDir);
        }
        
        return undefined;
    }
    
    /**
     * 运行当前方法的测试（如果游标位于一个测试方法上）
     */
    public async runCurrentMethod(debug: boolean): Promise<void> {
        const editor = vscode.window.activeTextEditor;
        if (!editor) {
            vscode.window.showErrorMessage('没有打开的文件');
            return;
        }
        
        // 获取当前游标位置
        const position = editor.selection.active;
        const document = editor.document;
        
        // 查找游标所在的方法
        const methodInfo = this.findMethodAtPosition(document, position);
        if (!methodInfo) {
            vscode.window.showInformationMessage('请将游标放在测试方法内');
            return;
        }
        
        // 解析测试类信息
        const classInfo = await this.parseJavaFile(document.fileName);
        if (!classInfo) {
            vscode.window.showErrorMessage('无法解析测试类信息');
            return;
        }
        
        // 查找POM文件
        const pomFile = await this.findPomFile(document.fileName);
        if (!pomFile) {
            vscode.window.showErrorMessage('找不到关联的POM文件');
            return;
        }
        
        // 构建测试命令，包含方法名
        const testName = `${classInfo.packageName}.${classInfo.className}#${methodInfo.name}`;
        let mavenCommand = `test -Dtest=${testName}`;
        
        if (debug) {
            mavenCommand += ' -Dmaven.surefire.debug';
        }
        
        // 在终端中执行
        const terminal = vscode.window.createTerminal(`Maven Test: ${methodInfo.name}`);
        const mvn = await this.mavenUtils.getMavenExecutable();
        const pomDir = path.dirname(pomFile);
        
        terminal.sendText(`cd "${pomDir}"`);
        terminal.sendText(`${mvn} ${mavenCommand}`);
        terminal.show();
    }
    
    /**
     * 查找在指定位置的方法
     */
    private findMethodAtPosition(document: vscode.TextDocument, position: vscode.Position): { name: string } | null {
        // 这里需要更复杂的解析，这只是一个简化的示例
        // 在实际应用中，可能需要使用Java解析器或正则表达式
        
        // 获取当前行的上一行，查找可能的方法声明
        let lineIndex = position.line;
        while (lineIndex >= 0) {
            const line = document.lineAt(lineIndex).text;
            const methodMatch = line.match(/\s*(public|private|protected)?\s*\w+\s+(\w+)\s*\(/);
            
            if (methodMatch) {
                return { name: methodMatch[2] };
            }
            
            lineIndex--;
        }
        
        return null;
    }
}
